package com.topscomm.file.service;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.topscomm.basic.exception.ServiceException;
import com.topscomm.file.util.YamUtil;
import com.topscomm.meet.MeetSystemConst.FileUploadStateEnum;
import com.topscomm.meet.service.IFileManageService;
import com.topscomm.pub.util.ConvertUtil;
import com.topscomm.pub.util.SecurityUtil;
import com.topscomm.pub.util.SpringUtil;
import com.topscomm.pub.util.StringBufferProxy;
import com.topscomm.tap.common.ParameterCache;

import cn.hutool.core.io.FileUtil;
import lombok.extern.slf4j.Slf4j;
import net.bramp.ffmpeg.FFmpeg;
import net.bramp.ffmpeg.FFmpegExecutor;
import net.bramp.ffmpeg.builder.FFmpegBuilder;
import net.bramp.ffmpeg.job.FFmpegJob;

/**
 * 文件切片服务处理链
 * 
 * @description:
 * @author: donghang
 * @date: 2020年8月20日上午10:50:05
 * @modify:
 */
@Slf4j
public class FileSpliceFilter implements IFileProcessFilter {
	/**
	 * ffmpeg路径
	 */
	private String ffmpegPath;
	/**
	 * enc路径
	 */
	private String encPath;
	/**
	 * 切片间隔
	 */
	private String duration;
	/**
	 * 根路径
	 */
	private String rootPath;
	/**
	 * 播放相对路径
	 */
	private String playRelativePath;

	private String rootUrlTag = "${url}";

	/**
	 * @description:
	 * @author: donghang
	 * @date: 2020年8月21日上午11:34:03
	 * @modify:
	 */
	public FileSpliceFilter() {
		this.ffmpegPath = YamUtil.getVal("file.audio.ffmpeg.path");
		this.duration = YamUtil.getVal("file.audio.ffmpeg.duration");
		this.rootPath = YamUtil.getVal("file.audio.root.path");
		this.encPath = YamUtil.getVal("file.audio.enc.path");
		this.playRelativePath = YamUtil.getVal("file.audio.root.playpath");
	}

	/**
	 * 切片处理
	 * 
	 * @description:
	 * @param paraMap
	 * @param dataProcessChain
	 * @return
	 * @author: donghang
	 * @date: 2020年8月20日下午12:50:24
	 * @modify:
	 */
	@Override
	public boolean doProcess(Map<String, Object> paraMap, IFileProcessChain dataProcessChain) {
		String fileName = ConvertUtil.convertToString(paraMap.get("fileName"));
		String identifier = ConvertUtil.convertToString(paraMap.get("identifier"));
		String sourceid = ConvertUtil.convertToString(paraMap.get("sourceid"));
		String sourcetype = ConvertUtil.convertToString(paraMap.get("sourcetype"));
		String location = ConvertUtil.convertToString(paraMap.get("foldername"));
		StringBuilder fileDirPath = new StringBuilder();
		StringBuilder filePath = new StringBuilder();
		// 原文件
		String inputFilePath = filePath.append(this.rootPath).append("/").append(location).append("/").append(fileName)
				.toString();
		File file = new File(inputFilePath);
		IFileManageService fileManageService = (IFileManageService) SpringUtil.getBean("fileManageService");
		if (!file.exists()) {
			Map<String, Object> updataMap = new HashMap<String, Object>();
			updataMap.put("uploadstate", FileUploadStateEnum.Finish);
			StringBufferProxy sql = new StringBufferProxy();
			sql.appendSingle(" 1=1 ");
			sql.appendSingle(" and identifier = '{0}' and sourceid='{1}' and sourcetype='{2}'", identifier, sourceid,
					sourcetype);
			fileManageService.updateByWhere(updataMap, sql.toString());
			log.error("ffmpeg原文件：" + inputFilePath + "已经切片");
			dataProcessChain.doProcess(paraMap);
			return true;
		}
		// 切片文件夹
		String spliceFolder = fileDirPath.append(this.rootPath).append("/").append(location).append("/splice")
				.toString();
		File outputDir = new File(spliceFolder);
		if (!outputDir.exists()) {
			outputDir.mkdirs(); // 创建目录
		} else {
			outputDir.delete();
			outputDir.mkdirs();
		}
		// 建造者模式分片处理
		String tempFilePath = spliceFolder + "/output.ts";
		String tempMp3FilePath = spliceFolder + "/output.mp3";
		String targetFilePath = spliceFolder + "/output_%d.ts";
		String m3u8FilePath = spliceFolder + "/output.m3u8";
		String tsFolderPath = spliceFolder + "/video/";
		File tsFoldeDir = new File(tsFolderPath);
		if (!tsFoldeDir.exists()) {
			tsFoldeDir.mkdirs(); // 创建目录
		}
		try {
			// 1.判断是否需要转换
			FFmpegBuilder builder = null;
			FFmpegExecutor executor = null;
			FFmpegJob job = null;
			String convertMp3FileParams = ParameterCache.getValue("FileAudioSpliceConvertFile", "aac");
			String inputFileExtension = inputFilePath.substring(inputFilePath.lastIndexOf(".") + 1,
					inputFilePath.length());
			if (convertMp3FileParams.toLowerCase().contains(inputFileExtension.toLowerCase())) {
				builder = new FFmpegBuilder().addInput(inputFilePath).overrideOutputFiles(true)
						.addOutput(tempMp3FilePath).addExtraArgs("-acodec", "libmp3lame").done();
				executor = new FFmpegExecutor(new FFmpeg(this.ffmpegPath));
				job = executor.createJob(builder, progress -> System.out.println("Progress: " + progress));
				job.run();
				// 2.首先切片成ts
				builder = new FFmpegBuilder().addInput(tempMp3FilePath).overrideOutputFiles(true)
						.addOutput(tempFilePath).addExtraArgs("-vcodec", "copy", "-acodec", "copy").done();
			} else {
				// 2.首先切片成ts
				builder = new FFmpegBuilder().addInput(inputFilePath).overrideOutputFiles(true).addOutput(tempFilePath)
						.addExtraArgs("-vcodec", "copy", "-acodec", "copy").done();
			}
			executor = new FFmpegExecutor(new FFmpeg(this.ffmpegPath));
			job = executor.createJob(builder, progress -> System.out.println("Progress: " + progress));
			job.run();
			File tempMp3File = new File(tempMp3FilePath);
			if (tempMp3File.exists()) {
				tempMp3File.delete();
			}
			if (job.getState() == FFmpegJob.State.FINISHED) {
				// 3.ts切片成hls "-hls_playlist_type", "vod",
				builder = new FFmpegBuilder().addInput(tempFilePath).overrideOutputFiles(true).addOutput(m3u8FilePath)
						.addExtraArgs("-c", "copy", "-f", "hls", "-hls_list_size", "0", "-hls_time", this.duration,
								"-hls_key_info_file", this.encPath, "-hls_segment_filename", targetFilePath)
						.done();
				executor = new FFmpegExecutor(new FFmpeg(this.ffmpegPath));
				job = executor.createJob(builder, progress -> System.out.println("Progress: " + progress));
				job.run();
				String prefix = String.format("%s/%s/%s/splice/", rootUrlTag, this.playRelativePath, location);
				// fileEncrypt(m3u8FilePath, "");
				fileEncrypt(m3u8FilePath, prefix);
				// 修改文件状态
				Map<String, Object> updataMap = new HashMap<String, Object>();
				updataMap.put("uploadstate", FileUploadStateEnum.Finish);
				StringBufferProxy sql = new StringBufferProxy();
				sql.appendSingle(" 1=1 ");
				sql.appendSingle(" and identifier = '{0}' and sourceid='{1}' and sourcetype='{2}'", identifier,
						sourceid, sourcetype);
				fileManageService.updateByWhere(updataMap, sql.toString());
				log.info("切片文件：" + inputFilePath + " 完成");
				File tempFile = new File(tempFilePath);
				tempFile.delete();
				dataProcessChain.doProcess(paraMap);
				return true;
			}
		} catch (IOException e) {
			log.error("ffmpeg切片异常" + e.getMessage());
			throw new ServiceException(e.getMessage());
		}
		return true;
	}

	/**
	 * @description:文件内容加密
	 * @param fileName
	 * @author: zhanglongfei
	 * @date: 2020年9月4日下午7:48:31
	 * @modify:
	 */
	private void fileEncrypt(String fileName, String prefix) {
		try {
			List<String> list = FileUtil.readLines(fileName, "UTF-8");
			StringBuilder sBuilder = new StringBuilder();
			list.forEach(m -> {
				if (m.endsWith(".ts")) {
					sBuilder.append(prefix + m + "\r\n");
				} else {
					sBuilder.append(m + "\r\n");
				}
			});
			String secretKey = ParameterCache.getValue("m3u8SecretKey", "12345678901234567890123456789012");
			byte[] secretContent = SecurityUtil.encryptDes(sBuilder.toString().getBytes(), secretKey);
			// byte[] secretContent = sBuilder.toString().getBytes();
			FileUtil.writeBytes(secretContent, new File(fileName), 0, secretContent.length, false);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
